/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jni;

/**
 * This class is implemented in JNI. This provides the Java interface
 * to invoke functions in JNI.
 * This file is used to generated the .h files required for jni. Avoid all
 * external dependencies in this file.
 * gandiva jni wrapper: <a href="https://github.com/apache/arrow/blob/master/java/gandiva/src/main/java/org/apache/arrow/gandiva/evaluator/JniWrapper.java">gandiva JniWrapper.java</a>
 */
public class JniWrapper {
    private static final JniWrapper INSTANCE = new JniWrapper();

    public static JniWrapper get() {
        JniLoader.get().ensureLoaded();
        return INSTANCE;
    }

    private JniWrapper() {}

    /**
     * simple jni method to test jni call overhead
     */
    public native void dummyCall();
    public native byte[] dummyCall(byte[] memoryAddress);
    public native char[] dummyCall(char[] memoryAddress);
    public native int[] dummyCall(int[] memoryAddress);
    public native long[] dummyCall(long[] memoryAddress);
    public native String[] dummyCall(String[] memoryAddress);
    public native DummyData objectCall(DummyData dummyData);

    /**
     * call a java method in jni
     * refer: gandiva JniWrapper.evaluateProjector
     * @param expander VectorExpander object
     * @param index vector index
     * @param toCapacity vector target capacity
     */
    public native void callVectorExpander(Object expander, long memoryAddress, long length, int index, long toCapacity);

    /**
     * Generates the projector module to evaluate the expressions with
     * custom configuration.
     *
     * @param schemaBuf   The schema serialized as a protobuf. See Types.proto
     *                    to see the protobuf specification
     * @param exprListBuf The serialized protobuf of the expression vector. Each
     *                    expression is created using TreeBuilder::MakeExpression.
     * @param selectionVectorType type of selection vector
     * @param configId    Configuration to gandiva.
     * @return A moduleId that is passed to the evaluateProjector() and closeProjector() methods
     *
     */
    native long buildProjector(byte[] schemaBuf, byte[] exprListBuf,
                               int selectionVectorType,
                               long configId) throws JniException;

    /**
     * Evaluate the expressions represented by the moduleId on a record batch
     * and store the output in ValueVectors. Throws an exception in case of errors
     *
     * @param expander VectorExpander object. Used for callbacks from cpp.
     * @param moduleId moduleId representing expressions. Created using a call to
     *                 buildNativeCode
     * @param numRows Number of rows in the record batch
     * @param bufAddrs An array of memory addresses. Each memory address points to
     *                 a validity vector or a data vector (will add support for offset
     *                 vectors later).
     * @param bufSizes An array of buffer sizes. For each memory address in bufAddrs,
     *                 the size of the buffer is present in bufSizes
     * @param outAddrs An array of output buffers, including the validity and data
     *                 addresses.
     * @param outSizes The allocated size of the output buffers. On successful evaluation,
     *                 the result is stored in the output buffers
     */
    native void evaluateProjector(Object expander, long moduleId, int numRows,
                                  long[] bufAddrs, long[] bufSizes,
                                  int selectionVectorType, int selectionVectorSize,
                                  long selectionVectorBufferAddr, long selectionVectorBufferSize,
                                  long[] outAddrs, long[] outSizes) throws JniException;

    /**
     * Closes the projector referenced by moduleId.
     *
     * @param moduleId moduleId that needs to be closed
     */
    native void closeProjector(long moduleId);
}
